package cn.com.huzo.service.hr.impl;

import cn.com.huzo.model.entities.hr.LeaveApplicationEntity;
import cn.com.huzo.model.entities.oa.ToDoEntity;
import cn.com.huzo.repository.hr.LeaveApplicationRepository;
import cn.com.huzo.service.hr.LeaveApplicationManager;
import huzofw.model.entities.paginator.Paginator;
import huzofw.service.impl.GenericManagerImpl;
import huzofw.service.workflow.ProcessApproveCommentManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 请假单管理服务对象类实现。
 *
 * @author 吴旭
 */
@Service("LeaveApplicationManager")
public class LeaveApplicationManagerImpl extends GenericManagerImpl<LeaveApplicationEntity, String>
        implements LeaveApplicationManager {

    private final String _key = "leave";
    @Resource(name = "LeaveApplicationRepository")
    private LeaveApplicationRepository _dao;

    @Autowired
    private IdentityService identityService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;

    @Resource(name = "ProcessApproveCommentManager")
    private ProcessApproveCommentManager _manager_proc_approve_comment;

    /**
     * {@inheritDoc}
     *
     * @throws java.lang.Exception
     */
    @Transactional
    @Override
    public Map<String, Object> fetchByHeaderKey(String key) throws Exception {
        Map<String, Object> _result = new HashMap();
        LeaveApplicationEntity _entity = _dao.fetchByKey(key);
        _result.put("LeaveApplicationEntity", _entity);
        _result.put("ProcApproveComment", _manager_proc_approve_comment.fetchProcessApproveComment(_entity.getProcessInstanceId()));
        return _result;
    }

    /**
     * {@inheritDoc}
     *
     * @throws java.lang.Exception
     */
    @Transactional
    @Override
    public Map<String, Object> fetchForPage(Map<String, Object> criterion) throws Exception {
        Map<String, Object> rtnValue = new HashMap();

        Long offset = (long) (MapUtils.getInteger(criterion, "Limit") * (MapUtils.getInteger(criterion, "PageIndex") - 1));
        long total = _dao.fetchForCount(criterion);

        if (total > 0) {
            if (offset >= total) {
                offset = (total - MapUtils.getInteger(criterion, "Limit")) < 0 ? 0 : (total - MapUtils.getInteger(criterion, "Limit"));
            }
            criterion.put("Offset", offset);
            List<LeaveApplicationEntity> itemList = _dao.fetchForPage(criterion);
            Paginator<LeaveApplicationEntity> paginator = new Paginator<>(itemList, offset, MapUtils.getInteger(criterion, "Limit"), total);

            rtnValue.put("TotalRecordCount", paginator.getTotal());
            rtnValue.put("TotalPages", paginator.getTotalPages());
            rtnValue.put("PageIndex", paginator.getPageIndex());
            rtnValue.put("DataList", paginator.getItemList());
            rtnValue.put("Success", true);
        } else {
            rtnValue.put("Success", false);
        }

        return rtnValue;
    }

    /**
     * {@inheritDoc}
     *
     * @throws java.lang.Exception
     */
    @Transactional
    @Override
    public Integer update(LeaveApplicationEntity instance) throws Exception {
        Integer rowsAffected = _dao.update(instance);

        if (rowsAffected > 0) {
            // 调整后重新申请
            taskService.complete(instance.getTaskId());
        }

        return rowsAffected;
    }

    /**
     * {@inheritDoc}
     *
     * @throws java.lang.Exception
     */
    @Transactional
    @Override
    public Integer delete(LeaveApplicationEntity instance) throws Exception {
        return _dao.delete(instance.getLeaveApplicationId());
    }

    /**
     * {@inheritDoc}
     *
     * @throws java.lang.Exception
     */
    @Transactional
    @Override
    public Map<String, Object> startWorkflow(LeaveApplicationEntity application, Integer limit, Integer pageIndex) throws Exception {
        // 第一步：创建请假单并使用请假单的主键作为businesskey,连接业务数据和流程数据
        String businessKey = _dao.insert(application);
        // 第二步：启动请假申请流程
        Map<String, Object> variables = new HashMap();
        variables.put("applyuserid", application.getUserId());
        variables.put("applyusername", application.getUserName());
        // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
        identityService.setAuthenticatedUserId(application.getUserId().toString());
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(_key, businessKey, variables);
        // 第三步：在请假单中保存流程ID
        _dao.setProcessInstanceId(businessKey, instance.getId());

        Map<String, Object> criterion = new HashMap();
        criterion.put("UserId", application.getUserId());
        criterion.put("Limit", limit);
        criterion.put("PageIndex", pageIndex);
        return fetchForPage(criterion);
    }

    /**
     * {@inheritDoc}
     *
     * @throws java.lang.Exception
     */
    @Transactional
    @Override
    public Map<String, Object> fetchDeptTaskForPage(Map<String, Object> criterion) throws Exception {
        // 任务候选人  
        String candidate = "部门经理";
        Map<String, Object> rtnValue = new HashMap();
        TaskQuery query = taskService.createTaskQuery().taskCandidateGroup(candidate).orderByTaskCreateTime().desc();

        Long offset = (long) (MapUtils.getInteger(criterion, "Limit") * (MapUtils.getInteger(criterion, "PageIndex") - 1));
        long total = taskService.createTaskQuery().taskCandidateGroup(candidate).count();

        if (total > 0) {
            if (offset >= total) {
                offset = (total - MapUtils.getInteger(criterion, "Limit")) < 0 ? 0 : (total - MapUtils.getInteger(criterion, "Limit"));
            }
            criterion.put("Offset", offset);
            List<Task> toDoTasks = query.listPage(offset.intValue(), MapUtils.getInteger(criterion, "Limit"));
            List<ToDoEntity> toDoList = new ArrayList();
            toDoTasks.stream().map((task) -> {
                ToDoEntity item = new ToDoEntity();
                item.setTaskId(task.getId());
                return item;
            }).forEachOrdered((item) -> {
                toDoList.add(item);
            });
            //toDoTasks.stream().map((task) -> task.getProcessInstanceId()).map((instanceid) -> runtimeService.createProcessInstanceQuery().processInstanceId(instanceid).singleResult()).map((ins) -> ins.getBusinessKey()).map((businesskey) -> _dao.fetchByKey(businesskey)).forEachOrdered((item) -> {
            //item.setTask(task);
            //    leaveItems.add(item);
            //});
            //for (Task task : toDoTasks) {
            //    LeaveApplicationEntity leaveItem = _dao.fetchByKey(runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult().getBusinessKey());
            //    leaveItems.add(leaveItem);
            //}
            Paginator<ToDoEntity> paginator = new Paginator<>(toDoList, offset, MapUtils.getInteger(criterion, "Limit"), total);

            rtnValue.put("TotalRecordCount", paginator.getTotal());
            rtnValue.put("TotalPages", paginator.getTotalPages());
            rtnValue.put("PageIndex", paginator.getPageIndex());
            rtnValue.put("DataList", paginator.getItemList());
            rtnValue.put("Success", true);
        } else {
            rtnValue.put("Success", false);
        }

        return rtnValue;
    }

    /**
     * {@inheritDoc}
     *
     * @throws java.lang.Exception
     */
    @Transactional
    @Override
    public Map<String, Object> handleTask(Long approvUserId, Long startUserId, String taskId, String processInstancesId,
            Boolean approve, String flowName, String comment) throws Exception {
        // Authentication.setAuthenticatedUserId(userId.toString());  // 添加批注时候的审核人
        // 用来设置添加批注时候的审核人，引擎会自动把用户ID保存到activiti:initiator中
        identityService.setAuthenticatedUserId(approvUserId.toString());

        Map<String, Object> variables = new HashMap(); // 流程存储参数
        if ("部门审批".equals(flowName)) {
            variables.put("deptleaderapprove", approve);
        }
        if ("人事审批".equals(flowName)) {
            variables.put("hrapprove", approve);
            // 动态指定任务办理人, 只要在任务完成的时候传递activiti:assignee属性中的变量即可
            //HistoricProcessInstance hi = historyService.createHistoricProcessInstanceQuery().singleResult();
            // hi.getStartUserId()
            // 这里设置的是流程发起人
            variables.put("applyuserid", startUserId.toString());
        }
        // 设置审批意见
        taskService.addComment(taskId, processInstancesId, comment);
        // 完成当前待办的任务状态
        taskService.complete(taskId, variables);

        Map<String, Object> _result = new HashMap();
        _result.put("success", true);
        return _result;
    }

    /**
     * {@inheritDoc}
     *
     * @throws java.lang.Exception
     */
    @Transactional
    @Override
    public Integer reapply(LeaveApplicationEntity instance) throws Exception {
        Integer rowsAffected = _dao.update(instance);

        if (rowsAffected > 0) {
            Map<String, Object> variables = new HashMap(); // 流程存储参数
            variables.put("reapply", instance.getReapply());
            // 调整后重新申请
            taskService.complete(instance.getTaskId(), variables);
        }

        return rowsAffected;
    }
}
